/* 
 * File:   queue.cpp
 * Author: landry
 * 
 * Created on 10 octobre 2009, 09:08
 */

#include <list>


//using namespace std;

#include "queue.h"


Queue::Queue() {
}

Queue::Queue(const Queue& orig) {
}

Queue::Queue(int nombreServeur) {
    //on initialise le nombre de clients en file a 0
   
    nbrClient_queued = 0;

    this->number_of_server = nombreServeur;
    this->time_last_arrival = 0;
    nbre_client_servi = 0;
  
    this->time_last_event = 0;
    this->time_in_queue = 0;
    this->nbre_cli_servi = 0;
    this->nbre_serveur_occupee = 0;
    this->durre_occup_serveur = 0;
    this->client_stayed_in_queued = 0;
    if(nbre_client_limite > clients.size() -1)
        nbre_client_limite = clients.size()-1;
    
}

void Queue::initQueue(int time_last_arrival,int elaps_time_last_departure,int time_to_new_departure){
        this->time_last_arrival = time_last_arrival;
        this->elaps_time_last_departure = elaps_time_last_departure;
        this->time_to_new_departure = time_to_new_departure;
    }


void Queue::initStatistique(){
    Statistiques st;
    st.event.cType ='b';
    st.event.instant = 0;
    st.event.num_client = -1;
    st.event.num_event = 0;
    st.client_queued = 0;//nombre de clients reste dans la fille
    st.occupied_time = 0; //duree integrale d'utilisation du serveur
    st.time_in_queue = 0; //duree integrale d'attente dans la queue
    
    Evenements initial;
    
    initial.cType = 'b';//begining
    initial.instant = 0;
    initial.num_client = -1;
    initial.num_event = 0;

    ListeEvenements.push_back(initial);
}


/* Operarion Sur la liste des clients
 * Il s'agit de :
 * - Suppression d'un client
 * - Ajout d'un client
 * - Calcul du temps de depart de ce clients
 */
void Queue::addClient(CLIENTS client){
    this->clientList.push_back(client);
}

void Queue::removeClient(){
    //On retire toujour le client en tete de liste
    this->clientList.pop_front();
}

int Queue::longueurMaxfile(){
    int max = 0;
    
    list<Statistiques>::iterator t;
    for(t = listStatistic.begin();t != listStatistic.end();t++){
            Statistiques cl = *t;
            if(cl.queue_length > max)
                max = cl.queue_length;

        }
    return max;
}

void Queue::displayStat(char* output_file){
    list<Statistiques>::iterator t;
    FILE*out;
    cout << " " <<::endl;

    cout << "Fin de la simulation ..... Affichage des statistiques du syteme" <<::endl;

   cout << " " <<::endl;

       if(strcmp(output_file,"null")!= 0) { 
	// if(output_file == NULL) { 
	
	 if(strcmp(output_file,"stdout") == 0)
    		out = stdout;
    	else
    		out = fopen(output_file,"w+");  

	  fprintf(out,"  \n");
	  fprintf(out," Legende :\n");
	  fprintf(out," Q(t) : Longueuer de la file d'attente a l'instant t \n");
	  fprintf(out," B(t) : Nombre de serveurs occupe a l'instant t \n");
	  fprintf(out," Toccupe : Duree integrale d'occupation du serveur \n");
	  fprintf(out," Tsomme : Duree integrale d'attente dans la queue \n");
	  fprintf(out," Nq : Nombre de clients restes dans la queue \n");
	  fprintf(out,"  \n");
	
	
	  fprintf(out," Detail de l'execution du programme \n");
	   

	  fprintf(out,"  \n");


	  fprintf(out,"%8s %10s %10s %10s %7s %7s %12s %12s %6s %30s\n","No Evenement","Horloge","No_client","Type_event","Q(t)","B(t)","Toccupe","Tsomme","Nq","Calendrier evenements");

               
    list<Evenements>::iterator iter;
    
    char *evt = (char*) malloc (sizeof(char)*10000);	
    char *subev = (char*) malloc (sizeof(char)*10000);

    for(t = listStatistic.begin();t != listStatistic.end();t++){
            Statistiques cl = *t;
	    
            if((cl.event.num_client != -1) && (cl.event.num_client != -2)){	
		evt[0]=' '; evt[1]='\0';			
		subev[0]=' ';subev[1]= '\0';
		int k=0;
		for(iter=cl.liste.begin();iter != cl.liste.end();iter++){
             		Evenements eve = *iter;
			if(eve.num_client == -2)
				sprintf(subev,"(%d,-,Stop)",eve.instant,eve.num_client,eve.cType);  
			else
				sprintf(subev,"(%d,%d,%c)",eve.instant,eve.num_client,eve.cType);  
                  	strcat(evt,subev); 
			strcat(evt," ");
			k++;   
			        
             	}

                fprintf(out,"%12d %10d %10d %10c %7d %7d %12d %12d %6d %30s\n",cl.event.num_event,cl.event.instant,cl.event.num_client,cl.event.cType,cl.queue_length ,cl.nbre_serveur_occupe,cl.occupied_time,cl.time_in_queue,cl.client_queued,evt);
                
		cout <<" " << endl;
            
            }

            else
                if((cl.event.num_client == -1)){
			
			evt[0]=' '; evt[1]='\0';						
			int k=0;
			for(iter=cl.liste.begin();iter != cl.liste.end();iter++){
             			Evenements eve = *iter;
				if(eve.num_client == -2)
				sprintf(subev,"(%d,-,Stop)",eve.instant,eve.num_client,eve.cType);  
				else
				sprintf(subev,"(%d,%d,%c)",eve.instant,eve.num_client,eve.cType);                   		
				strcat(evt,subev); 
				//cout << 
				strcat(evt," ");
				k++;   
			        
             		}                	
			if(cl.event.cType != 'a' && cl.event.cType != 'd')
			fprintf(out,"%12d %10d %10s %10s %7d %7d %12d %12d %6d %30s\n",cl.event.num_event,cl.event.instant,"-","Start",cl.queue_length ,cl.nbre_serveur_occupe,cl.occupied_time,cl.time_in_queue,cl.client_queued,evt);
        		else
			fprintf(out,"%12d %10d %10d %10c %7d %7d %12d %12d %10d %30s\n",cl.event.num_event,cl.event.instant,cl.event.num_client,cl.event.cType,cl.queue_length ,cl.nbre_serveur_occupe,cl.occupied_time,cl.time_in_queue,cl.client_queued,evt);
			           
	             cout <<" " << endl;
            }

                else{
			evt[0]=' '; evt[1]='\0';			
			subev[0]=' ';subev[1]= '\0';
			int k=0;
			for(iter=cl.liste.begin();iter != cl.liste.end();iter++){
             			Evenements eve = *iter;
				sprintf(subev,"(%d,%d,%c)",eve.instant,eve.num_client,eve.cType);                    		
				strcat(evt,subev); 				
				strcat(evt," ");
				k++;   
			        
             		}                	
			if(cl.event.cType != 'a' && cl.event.cType != 'd')
			fprintf(out,"%12d %10d %10s %10s %7d %7d %12d %12d %6d %30s\n",cl.event.num_event,cl.event.instant,"-","Stop",cl.queue_length ,cl.nbre_serveur_occupe,cl.occupied_time,cl.time_in_queue,cl.client_queued,evt);
        		else
			fprintf(out,"%12d %10d %10d %10c %7d %7d %12d %12d %6d %30s\n",cl.event.num_event,cl.event.instant,cl.event.num_client,cl.event.cType,cl.queue_length ,cl.nbre_serveur_occupe,cl.occupied_time,cl.time_in_queue,cl.client_queued,evt);
			           

                }
                    

        }
	
    		delete evt;
    		delete subev;
	fprintf(out," \n");
	fprintf(out," \n");
	fprintf(out," Statistiques du systeme  \n");
	fprintf(out," \n");
    	fprintf(out,"Nombre de serveur :  %d \n", this->number_of_server);
    	fprintf(out, "Nombre total de clients servis :  %d \n", this->nbre_cli_servi);
    	float k = (float) this->listStatistic.back().occupied_time/this->listStatistic.back().event.instant;
    	float kk = (float) k/this->number_of_server;
    //if(this->number_of_server == 1){
       	fprintf(out,"Taux moyen d'occupation du serveur : %f \n",kk);
	
	

   	float ff = 0; 
   	float tt = 0; 
    	if(this->listStatistic.back().client_queued != 0)
    	tt = (float) this->listStatistic.back().time_in_queue/this->listStatistic.back().client_queued;

    	if(this->listStatistic.back().event.instant !=0 )     
		ff = (float) this->listStatistic.back().time_in_queue/this->listStatistic.back().event.instant;

   
    	fprintf(out,"Longueur moyenne de la file d'attente : %f \n",ff);
    	fprintf(out,"Temps moyen passe dans la file d'attente (Temps moyen d'attente) : %f\n",tt);
    	fprintf(out,"Longueur maximale de la file d'attente : %d \n",longueurMaxfile());
	//fprintf(out,"Longueur moyenne de la file d'attente : %f \n",ff);

	fprintf(out," \n");
	
	}


    if(strcmp(output_file,"null") == 0){
    
    cout << " " <<::endl;

    cout << "Nombre de serveur : " << this->number_of_server <<::endl;
    cout << "Nombre total de clients servis : " << this->nbre_cli_servi <<::endl;
    float k = (float) this->listStatistic.back().occupied_time/this->listStatistic.back().event.instant;
    float kk = (float) k/this->number_of_server;
    cout << "Taux moyen d'occupation du serveur : " << kk <<::endl;

   float ff = 0; 
   float tt = 0; 
    if(this->listStatistic.back().client_queued != 0)
    	tt = (float) this->listStatistic.back().time_in_queue/this->listStatistic.back().client_queued;

    if(this->listStatistic.back().event.instant !=0 )     
	ff = (float) this->listStatistic.back().time_in_queue/this->listStatistic.back().event.instant;

   
    cout << "Longueur moyenne de la file d'attente : "<< ff <<::endl;
    cout << "Temps moyen passe dans la file d'attente (Temps moyen d'attente): " << tt <<::endl;
    cout << "Longueur maximale de la file d'attente : " << longueurMaxfile() <<::endl;


   cout<< " " <<::endl;	
   cout<< " " <<::endl;
   }

}


void Queue::proccessEvent(Evenements event){

	
    

    //list<Evenements> liste;
    Statistiques stats;
    
    int num_client = event.num_client;

    //donne la duree d'occupation du serveur
    this->time_in_queue += (event.instant - this->time_last_event)*this->clientList.size();

    this->time_last_event = event.instant;

   //mise a jour de la duree d'occupation du serveur
    this->durre_occup_serveur += (event.instant - this->time_last_arrival)*this->nbre_serveur_occupee;

    CLIENTS c;
    //recherche du client correspondant  
    if(event.cType!='b' && event.cType!='s'){
    list<CLIENTS>::iterator it;

       

       int trouvee = -1;

       for(it=clients.begin();it != clients.end();it++){
            CLIENTS cl = *it;
            if(cl.num_cli == num_client){
                c.num_cli = cl.num_cli;
                c.tpsarrivee = cl.tpsarrivee;
                c.tpsservice = cl.tpsservice;
                break;
            }
        }
    }
        if(event.cType != 's'){


            if(event.cType =='b'){
                    Evenements evenetm;
               
                    CLIENTS cl = clients.front();
                              
                        evenetm.cType = 'a';//arrivee
                        evenetm.instant = cl.tpsarrivee;
                        evenetm.num_client = cl.num_cli;
                        evenetm.num_event = ++numeroEvenement;
                        //insertion de l'evenement de fin //modifier
                        ListeEvenements.push_front(evenetm);                        
                        horlogeSysteme.updeteHorloge();
                     if(arret == 0){ //la condition d'arret est le temps defini par le parametre t
                            Evenements eve;
                            eve.cType = 's';//arrivee
                            eve.instant = time_for_end;
                            eve.num_client = -2;//cl.num_cli;
                            eve.num_event = ++numeroEvenement;
                            ListeEvenements.push_back(eve);  //modifier                      
                            horlogeSysteme.updeteHorloge();
                     }
                    
            }
            else{    
            char event_type = event.cType;
            if(event_type =='a'){
                
             //arrivee suivante il s'agir du client en tete de liste de la liste des clients
            //le client suivant est a la position numeroclient courent +1
                if(num_client < (clients.size())){
                //on peut programmer l'arrivee suivante              
                Evenements evenetm;
                CLIENTS clte;
                list<CLIENTS>::iterator t;
                for(t=clients.begin();t != clients.end();t++){
                    CLIENTS cl = *t;
                    if(cl.num_cli == num_client +1){
                        //on prend son suivant dans la liste
                       
                        evenetm.cType = 'a';//arrivee
                        
                        evenetm.instant = event.instant + cl.tpsarrivee;
                        evenetm.num_client = cl.num_cli;
                        evenetm.num_event = ++numeroEvenement;
                        ListeEvenements.push_front(evenetm);//modifier                   

                        horlogeSysteme.updeteHorloge();
                        break;
                    }
                }
            }

           
            //recherche d'un serveur libre

          // int  get_server = this->server_free();
         
           if(this->nbre_serveur_occupee < this->number_of_server){ // la variable get_server contient le numero d'un serveur libre
               //fixe le numero du client en cours de service pour ce serveur
            
               //ajout du nombre de serveurs occupee
               this->nbre_serveur_occupee = this->nbre_serveur_occupee + 1;
           
              int tps_service = c.tpsservice;
            
              int curent_time = event.instant;
              int tps_depart = event.instant + tps_service;
              Evenements evt;
              evt.cType = 'd';
              evt.instant = tps_depart;
              evt.num_client = num_client;
              ListeEvenements.push_front(evt);
              //update horloge
              horlogeSysteme.updeteHorloge();

             
           }
           else{//pas de serveur libre

               //this->nbre_serveur_occupee  = this->nbre_serveur_occupee ;
               //ajout du client a la file d'attente
               this->clientList.push_back(c);
               //mise a jour du nombre de client queued
               this->queue_length = this->clientList.size();

           }

        }
        else{
            if(event_type == 'd'){
                this->nbre_cli_servi++;
                nbre_client_servi = this->nbre_cli_servi;
                
                //On teste si le nombre de clients maximum est atteint
                if(arret == 1){
                if(nbre_client_servi == nbre_client_limite){
                    //si la limite est atteinte, on introduit un evenement de fin dans la liste
                    //des evenements avant pour instant l'instant courant
                        Evenements e;
                        e.cType = 's';//arrivee
                        e.instant = event.instant+1;
                        e.num_client = -2;
                        e.num_event = ++numeroEvenement;
                        ListeEvenements.push_back(e);                    
                        horlogeSysteme.updeteHorloge();
                }
               }
                
               
                //liberation d'un serveur
               this->nbre_serveur_occupee =  this->nbre_serveur_occupee - 1;

                if(this->clientList.empty()){ // la file d'attente est vide

                }
                else{ // la file d'attente n'est pas vide
                    //recupere le numero d'un serveur libre

                    //verifi s'il ya un serveur disponible
                 
                    if(this->nbre_serveur_occupee <= this->number_of_server){//il ya un serveur libre
                        //On ne retire un client de la file que lorsqu'un serveur est libre
                       
                        CLIENTS client = this->clientList.front();
                        int cli_number = client.num_cli;


                        //On augmente le nombre de clients sortie de la file d'attente
                        this->client_stayed_in_queued += 1;

                        //on met le nombre de clients dans la file d'attente a jour
                        nbrClient_queued = this->clientList.size() -1;
                        
                        //etat du serveur mis a 1 => serveur occupe
                        //il suffit de dire que l'on a un serveur de plus
                        this->nbre_serveur_occupee = this->nbre_serveur_occupee + 1;

                         //Calclul de l'heure de depart du client en cours d'execution
                                              
                        int tps_service = client.tpsservice;
                        horlogeSysteme.updeteHorloge();
                        //recuperation du prochain instant
                     
                        int curent_time = event.instant;
                      
                        int tps_depart = curent_time + tps_service;
                                             
                        Evenements ev;
                        ev.cType = 'd';
                        ev.instant = tps_depart;
                        ev.num_client = client.num_cli;
                        ev.num_event = ++numeroEvenement;                    
                        ListeEvenements.push_front(ev);
                    
                        horlogeSysteme.updeteHorloge();                    
                        this->clientList.pop_front();

                    }
                  
                }
            }
        }
            }
    

         this->time_last_arrival = event.instant;

        
        //Statistiques stats;
        stats.client_queued = this->nbre_cli_servi;//nombre de clients restes dans la file        

        stats.nbre_serveur_occupe = this->nbre_serveur_occupee;

        
        stats.occupied_time = this->durre_occup_serveur;

        stats.time_in_queue = this->time_in_queue; //duree integrale d'attente dans la queue
        stats.event.cType = event.cType; // type d'evenement
        stats.event.instant = event.instant; // instant auquel s'est produit l'evenement
        stats.event.num_client = num_client; // numero du client concerne
        stats.event.num_event = this->listStatistic.size();//event.num_event; // numero d'evenement
        stats.queue_length = this->clientList.size();//to do

        stats.client_queued = this->client_stayed_in_queued;

	 list<Evenements>::iterator iterator;


      for(iterator=ListeEvenements.begin();iterator != ListeEvenements.end();iterator++){
            Evenements E = *iterator;      
            stats.liste.push_back(E);        
      }


        this->listStatistic.push_back(stats);

    }
      //  }
    else{
            if(event.cType == 's'){
               // Statistiques stats;

                stats.client_queued = this->nbre_cli_servi;//nombre de clients restes dans la file
             
                list<Evenements>::iterator iterator;
             
                for(iterator=ListeEvenements.begin();iterator != ListeEvenements.end();iterator++){
                 	Evenements E = *iterator;               
                	stats.liste.push_back(E);     	
                }

                stats.occupied_time = this->durre_occup_serveur;

                stats.time_in_queue = this->time_in_queue; //duree integrale d'attente dans la queue
                stats.event.cType = 's'; // type d'evenement
                stats.event.instant = event.instant; // instant auquel s'est produit l'evenement
                stats.event.num_client = -2; // numero du client concerne
                stats.event.num_event = this->listStatistic.size();//event.num_event; // numero d'evenement
                stats.queue_length = this->clientList.size();//to do
                stats.nbre_serveur_occupe = this->nbre_serveur_occupee;
                stats.client_queued = this->client_stayed_in_queued;
                this->listStatistic.push_back(stats);
                cont = false;
            }
        
    }

	
}
     


Queue::~Queue() {
}

